#include "SFilterButton.h"

#include <core/StyleMgr.h>

#include <QApplication>
#include <QColor>
#include <QMenu>
#include <QStylePainter>

namespace {
const int gap = 4;
const int buttonHeight = 24;
}  // namespace
SFilterLabel::SFilterLabel(int index, const QString& t, int id,
                           std::string userdata,
                           std::vector<SFilterSubMenuItem>* vctSub,
                           QWidget* parent /*= nullptr*/, funcMenuCheck func)
    : QLabel(t, parent), m_index(index), m_id(id), m_userdata(userdata) {
  setAlignment(Qt::AlignCenter);
  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  setMouseTracking(true);
  installEventFilter(this);

  if (vctSub) {
    m_menu = new QMenu(this);
    m_menu->setStyleSheet(
        QString("QMenu {border:1px solid "
                "#%4;background-color:#%4;color:#%5;border-radius:2px;margin:"
                "0px;}\n"
                "QMenu::item {padding:6px 38px 6px 18px;color:#%5;}\n"
                "QMenu::item:selected {background-color:#%1;}\n"
                "QMenu::item:disabled {color:#%2; background-color:#%4; "
                "border:1px solid #%4;}\n"
                "QMenu::item:checked {background-color:#%4; color:#%3; "
                "border:1px solid #%3;}\n"
                //	"QMenu::item:indicator::checked {background-color:#%4;
                //color:#%3; border:1px solid #%3;}\n"
                "QMenu::separator{height:1px; background:#%3; margin-left:0px; "
                "margin-right:0px;}")
            .arg(NAME_COLOR("Hover").rgb(), 0, 16)
            .arg(NAME_COLOR("TipsBorder").rgb(), 0, 16)
            .arg(NAME_COLOR("Highlight").rgb(), 0, 16)
            .arg(NAME_COLOR("BackNormal").rgb(), 0, 16)
            .arg(NAME_COLOR("TextNormal").rgb(), 0, 16));

    for (int i = 0; i < (int)vctSub->size(); ++i) {
      QAction* actionSub = new QAction((*vctSub)[i].name, this);
      m_menu->addAction(actionSub);
      actionSub->setCheckable(true);
      actionSub->setData((*vctSub)[i].id);
      m_vctSub.push_back(actionSub);
      connect(actionSub, &QAction::triggered, this, [=] { func(index); });
    }

    m_timer = new QTimer(this);
    m_timer->callOnTimeout(this, &SFilterLabel::onTimer);
  }
}

SFilterLabel::~SFilterLabel() {
  if (m_timer) {
    m_timer->stop();
  }
}

void SFilterLabel::selAllMenuItems(bool check) {
  for (int i = 0; i < (int)m_vctSub.size(); ++i) {
    m_vctSub[i]->setChecked(check);
  }

  if (0 == m_index) {
    if (!m_enable) {
      m_strStyle = styleSheet();
      setStyleSheet(
          QString("SFilterLabel {color:#%1; background-color:#%2;}")
              .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16)
              .arg(StyleMgr::instance().color("TabDisabled").rgb(), 0, 16));
    } else {
      setStyleSheet(m_strStyle);
    }
  } else if ((int)m_vctSub.size() > 0) {
    if (!m_enable) {
      setStyleSheet(
          QString("SFilterLabel {color:#%1; border:1px solid #%2;}")
              .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16)
              .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16));
    } else if (!check) {
      setStyleSheet(
          QString("SFilterLabel {color:#%1; border:1px solid #%2;}")
              .arg(StyleMgr::instance().color("TextNormal").rgb(), 0, 16)
              .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16));
    } else {
      setStyleSheet(
          QString("SFilterLabel {color:#%1; border:1px solid #%1;}")
              .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16));
    }
  }
}

void SFilterLabel::getChecked(std::vector<bool>& vctChecked) {
  for (int i = 0; i < (int)m_vctSub.size(); ++i) {
    vctChecked.push_back(m_vctSub[i]->isChecked());
  }
}

void SFilterLabel::getChecked(std::vector<int>& vctChecked) {
  vctChecked.clear();
  for (int i = 0; i < (int)m_vctSub.size(); ++i) {
    if (m_vctSub[i]->isChecked()) {
      vctChecked.push_back(m_vctSub[i]->data().toInt());
    }
  }
}

void SFilterLabel::setLabelEnable(bool enable) {
  m_enable = enable;
  setEnabled(enable);
}

void SFilterLabel::paintEvent(QPaintEvent* event) {
  QLabel::paintEvent(event);

  if (m_menu) {
    QPalette palette = QLabel::palette();
    QColor clrPen;

    if (isEnabled()) {
      clrPen = palette.color(QPalette::WindowText);
    } else {
      clrPen = StyleMgr::instance().color("TipsBorder");
    }

    QStylePainter painter(this);
    painter.setPen(clrPen);

    QFontMetrics fm(font());
    int width = fm.horizontalAdvance(text());
    int x = rect().center().x() + width / 2 + 4;
    int y = rect().center().y() - 1;
    painter.drawLine(QPointF(x, y), QPointF(x + 2, y + 2));
    painter.drawLine(QPointF(x, y + 4), QPointF(x + 2, y + 2));
  }
}

void SFilterLabel::mouseMoveEvent(QMouseEvent* event) {
  if (nullptr == m_menu) {
    return;
  }

  if (m_menu->isHidden()) {
    m_timer->stop();
    m_timer->start(500);
    m_menu->popup(mapToGlobal(rect().topRight()));
  }
}

void SFilterLabel::leaveEvent(QEvent* event) {
  if (nullptr == m_menu) {
    return;
  }

  if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
    m_menu->hide();
  }
}

void SFilterLabel::mousePressEvent(QMouseEvent* event) {
  if (event->button() == Qt::LeftButton) {
    bool bCtrlPress = false;
    if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) {
      bCtrlPress = true;
    }
    emit clicked(m_index, bCtrlPress);
  }

  return QLabel::mousePressEvent(event);
}

bool SFilterLabel::eventFilter(QObject* obj, QEvent* event) {
  if (!isVisible()) return false;

  switch (event->type()) {
    case QEvent::FocusOut: {
      //	if (m_menu && !m_menu->isHidden()) {
      //		setFocus();
      //	}
    } break;
    default:
      break;
  }

  return false;
}

void SFilterLabel::onTimer() {
  if (nullptr == m_menu) {
    m_timer->stop();
    return;
  }

  if (!rect().contains(mapFromGlobal(QCursor::pos())) &&
      !m_menu->rect().contains(mapFromGlobal(QCursor::pos()))) {
    m_menu->hide();
    m_timer->stop();
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

SFilterButton::SFilterButton(QWidget* p, QString strBkColor)
    : QFrame(p), m_nameWidth(0), m_strBkColor(strBkColor) {
  m_layout = new QFlowLayout(this, 0, 1, gap);

  m_styleSheet =
      QString(
          "SFilterLabel					{color:#%1; "
          "background-color:#%2;border:1px solid #%7;border-radius:2px}"
          "SFilterLabel:hover				{background-color:#%3}"
          "SFilterLabel:disabled			{color:#%4; "
          "background-color:#%8; border:1px solid #%2; border-radius:2px}"
          "SFilterLabel[selected=\"true\"]{color:#%5; background-color:#%6; "
          "border:1px solid #%5; border-radius:2px}")
          .arg(StyleMgr::instance().color("TextNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color(strBkColor).rgb(), 0, 16)
          .arg(StyleMgr::instance().color("Hover").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("TxtDisabled").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("BackNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color(strBkColor).rgb(), 0, 16)
          .arg(StyleMgr::instance().color("TabDisabled").rgb(), 0, 16);

  setStyleSheet(m_styleSheet);
}

void SFilterButton::setName(const QString& sName) {
  m_name = sName;
  if (m_name.isEmpty()) return;
  if (!m_layout) return;

  if (m_nameWidth <= 0) {
    QFontMetrics fmName(font());
    m_nameWidth = fmName.horizontalAdvance(m_name) + 16;
  }
  m_layout->setContentsMargins(m_nameWidth + gap, 0, 0, 0);
}

void SFilterButton::setNameWidth(int width) {
  m_nameWidth = width;
  m_layout->setContentsMargins(m_nameWidth + gap, 0, 0, 0);
}

void SFilterButton::addTab(const QString& name, int id, std::string userdata,
                           std::vector<SFilterSubMenuItem>* vctSub) {
  if (!m_layout) return;

  SFilterLabel* item = new SFilterLabel(
      m_labels.size(), name, id, userdata, vctSub, this,
      std::bind(&SFilterButton::onMenuChecked, this, std::placeholders::_1));
  QFontMetrics metrics(font());
  QRect txtR = metrics.boundingRect(name);

  if (vctSub) {
    item->setMinimumWidth(txtR.width() + 30);
    item->setContentsMargins(0, 0, 6, 0);
    item->setStyleSheet(
        QString("SFilterLabel {border:1px solid #%1;}")
            .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16));
  } else {
    item->setMinimumWidth(txtR.width());
    item->setContentsMargins(6, 0, 6, 0);
  }

  if (m_fixedWidth > 0) {
    item->setFixedWidth(m_fixedWidth);
  }

  item->setFixedHeight(buttonHeight);
  m_labels.push_back(item);

  if (m_layout) {
    m_layout->addWidget(item);
  }

  connect(item, &SFilterLabel::clicked, this, &SFilterButton::onTabClicked);
}

void SFilterButton::setTabFixedWidth(int width) { m_fixedWidth = width; }

void SFilterButton::selectTab(int index, bool bCtrlPress) {
  if (index < 0 || index >= (int)m_labels.size() || m_labels.size() <= 0)
    return;

  if (0 == index) {
    m_labels[0]->setStyleSheet(
        QString("SFilterLabel {background-color:#%1;}"
                "SFilterLabel[selected=\"true\"]{background-color:#%2;}")
            .arg(StyleMgr::instance()
                     .color(isEnabled() ? "TabBackNormal" : "TabDisabled")
                     .rgb(),
                 0, 16)
            .arg(StyleMgr::instance()
                     .color(isEnabled() ? "BackNormal" : "TabDisabled")
                     .rgb(),
                 0, 16));
  }

  if (!m_bVirtualHead) {
    if (index == 0) {
      m_labels[0]->setProperty("selected", "true");
      for (int i = 1; i < (int)m_labels.size(); ++i) {
        m_labels[i]->setProperty("selected", "false");
        m_labels[i]->selAllMenuItems(false);
      }
      setStyleSheet(m_styleSheet);
      return;
    } else {
      m_labels[0]->setProperty("selected", "false");
      m_labels[0]->selAllMenuItems(false);
    }
  }

  m_labels[index]->setProperty(
      "selected",
      (m_labels[index]->property("selected") == true) ? "false" : "true");

  if (true == m_labels[index]->property("selected")) {
    m_labels[index]->selAllMenuItems(true);
  } else {
    m_labels[index]->selAllMenuItems(false);
  }

  if (!m_bMultiSelect) {
    int orgSel = -1;
    for (int i = 1; i < (int)m_labels.size(); ++i) {
      if (index == i) continue;
      if (m_labels[i]->property("selected") == true) {
        orgSel = i;
        break;
      }
    }
    if (orgSel > 0) {
      m_labels[orgSel]->setProperty("selected", "false");
      m_labels[orgSel]->selAllMenuItems(false);
    }
  }

  if (!m_bVirtualHead && !m_bVirtualHead2) {
    int i = 1;
    for (i = 1; i < (int)m_labels.size(); ++i) {
      if (m_labels[i]->property("selected") == true) {
        break;
      }
    }
    if (i >= (int)m_labels.size()) {
      m_labels[0]->setProperty("selected", "true");
      m_labels[0]->selAllMenuItems(true);
    }
  }

  setStyleSheet(m_styleSheet);
}

void SFilterButton::selectAllTabs() {
  for (int i = 0; i < (int)m_labels.size(); ++i) {
    m_labels[i]->setProperty("selected", "true");
    m_labels[i]->selAllMenuItems(true);
  }

  setStyleSheet(m_styleSheet);
}

int SFilterButton::getTabCount() { return m_labels.size(); }

void SFilterButton::getSelTab(std::vector<int>& vctSel, bool includeSub) {
  vctSel.clear();
  for (int i = 0; i < (int)m_labels.size(); ++i) {
    if (m_labels[i]->property("selected") == true) {
      vctSel.push_back(i);
    }
    if (includeSub) {
      std::vector<int> vctSub;
      m_labels[i]->getChecked(vctSub);
      if ((int)vctSub.size() > 0) {
        vctSel.push_back(i);
      }
    }
  }
}

void SFilterButton::getSelTabId(std::vector<int>& vctSelId) {
  vctSelId.clear();

  for (int i = 0; i < (int)m_labels.size(); ++i) {
    if (m_labels[i]->hasSubMenu()) {
      std::vector<int> vctSub;
      m_labels[i]->getChecked(vctSub);
      for (int j = 0; j < (int)vctSub.size(); ++j) {
        vctSelId.push_back(vctSub[j]);
      }
    } else {
      if (m_labels[i]->property("selected") == true) {
        vctSelId.push_back(m_labels[i]->id());
      }
    }
  }
}

void SFilterButton::getSelTabName(std::vector<QString>& vctSelName) {
  vctSelName.clear();

  for (int i = 0; i < (int)m_labels.size(); ++i) {
    if (m_labels[i]->hasSubMenu()) {
      continue;
    } else {
      if (m_labels[i]->property("selected") == true) {
        vctSelName.push_back(m_labels[i]->text());
      }
    }
  }
}

void SFilterButton::getSelTabUserData(
    std::vector<std::string>& vctSelUserData) {
  vctSelUserData.clear();

  for (int i = 0; i < (int)m_labels.size(); ++i) {
    if (m_labels[i]->hasSubMenu()) {
      continue;
    } else {
      if (m_labels[i]->property("selected") == true) {
        if (m_labels[i]->userdata().length() > 0)
          vctSelUserData.push_back(m_labels[i]->userdata());
      }
    }
  }
}

bool SFilterButton::isSelected(int index, bool includeSub) {
  if (index < 0 || index >= (int)m_labels.size()) return false;
  if (m_labels[index]->property("selected") == true) {
    return true;
  }
  if (includeSub) {
    std::vector<int> vctSub;
    m_labels[index]->getChecked(vctSub);
    if ((int)vctSub.size() > 0) {
      return true;
    }
  }
  return false;
}

void SFilterButton::clearSelect() {
  for (int i = 0; i < (int)m_labels.size(); ++i) {
    m_labels[i]->setProperty("selected", "false");
    m_labels[i]->selAllMenuItems(false);
  }
  setStyleSheet(m_styleSheet);
}

void SFilterButton::changeSelect(int index, bool selected) {
  if (index < 0 || index >= (int)m_labels.size()) return;
  m_labels[index]->setProperty("selected", selected ? "true" : "false");
  m_labels[index]->selAllMenuItems(selected);
  setStyleSheet(m_styleSheet);

  if (0 == index && !selected) {
    m_labels[0]->setStyleSheet(
        QString("SFilterLabel {background-color:#%1;border:1px solid #%1;}")
            .arg(StyleMgr::instance()
                     .color(isEnabled() ? "TabBackNormal" : "TabDisabled")
                     .rgb(),
                 0, 16));
  }
}

void SFilterButton::enableAllTabs() {
  if (isEnabled()) {
    return;
  }
  setEnabled(true);

  for (int i = 0; i < (int)m_labels.size(); ++i) {
    m_labels[i]->setLabelEnable(true);
    if (i > 0) {
      m_labels[i]->selAllMenuItems(false);
    }
  }

  changeSelect(0, true);
}

void SFilterButton::disableAllTabs() {
  if (!isEnabled()) {
    return;
  }
  for (int i = 0; i < (int)m_labels.size(); ++i) {
    m_labels[i]->setLabelEnable(false);
    if (i > 0) {
      m_labels[i]->selAllMenuItems(false);
    }
  }

  clearSelect();
  setEnabled(false);
}

void SFilterButton::setMultiSel(bool multiSel) { m_bMultiSelect = multiSel; }

void SFilterButton::setVirtualHead() { m_bVirtualHead = true; }

void SFilterButton::setVirtualHead2() { m_bVirtualHead2 = true; }

void SFilterButton::onMenuChecked(int index) {
  if (index < 0 || index >= (int)m_labels.size()) return;

  bool bPart = false, allUnCheck = true;
  std::vector<bool> vctChecked;
  m_labels[index]->getChecked(vctChecked);
  for (int i = 0; i < (int)vctChecked.size(); ++i) {
    if (!vctChecked[i]) {
      bPart = true;
    } else {
      allUnCheck = false;
    }
  }

  if (allUnCheck) {
    m_labels[index]->setProperty("selected", "false");
    m_labels[index]->setStyleSheet(
        QString("SFilterLabel {color:#%1; border:1px solid #%2;}")
            .arg(StyleMgr::instance().color("TextNormal").rgb(), 0, 16)
            .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16));
  } else if (bPart) {
    m_labels[index]->setProperty("selected", "true");
    m_labels[index]->setStyleSheet(
        QString("SFilterLabel {color:#%1; border:1px solid #%2;}")
            .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16)
            .arg(StyleMgr::instance().color("TipsBorder").rgb(), 0, 16));
  } else {
    m_labels[index]->setProperty("selected", "true");
    m_labels[index]->setStyleSheet(
        QString("SFilterLabel {color:#%1; border:1px solid #%1;}")
            .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16));
  }

  setStyleSheet(m_styleSheet);
  emit tabSelected(index);
}

void SFilterButton::onTabClicked(int index, bool bCtrlPress) {
  selectTab(index, bCtrlPress);
  emit tabSelected(index);
}

void SFilterButton::paintEvent(QPaintEvent* event) {
  if (m_name.length() <= 0) return;

  QStylePainter painter(this);
  QRect rc(0, 0, m_nameWidth, buttonHeight);
  QColor bkColor = NAME_COLOR("StaticTextBK");
  painter.setPen(Qt::NoPen);
  painter.setBrush(bkColor);
  painter.drawRoundedRect(rc, 2, 2);

  rc.setLeft(rc.left() + 8);

  if (isEnabled()) {
    painter.setPen(StyleMgr::instance().color("TitleWord"));
  } else {
    painter.setPen(StyleMgr::instance().color("TipsBorder"));
  }

  painter.drawText(rc, m_name, QTextOption(Qt::AlignLeft | Qt::AlignVCenter));
}
